/*
 * comath.c
 *
 *  Created on: 2015��8��25��
 *      Author: huangkaibin
 */

#include "comath.h"
#include "cobit.h"

#define CRC32_TABLE_SIZE_MASK	(0xF)
#define CRC_INDEX_BITS 			(4)

static const uint32 CRC32_TABLE[16] = {
		0x00000000,
		0x04c11db7,
		0x09823b6e,
		0x0d4326d9,
		0x130476dc,
		0x17c56b6b,
		0x1a864db2,
		0x1e475005,
		0x2608edb8,
		0x22c9f00f,
		0x2f8ad6d6,
		0x2b4bcb61,
		0x350c9b64,
		0x31cd86d3,
		0x3c8ea00a,
		0x384fbdbd
};

uint8 calc_floor_log2(uint16 data) {
	uint16 mask = (1U << 15U);
	uint8 upper_pos = 0U;
	uint8 pos = 15U;
	while(mask > 0U) {
		if((data & mask) != 0U) {
			upper_pos = pos;
			break ;
		}
		pos--;
		mask >>= 1U;
	}
	return upper_pos;
}

uint8 calc_ceil_log2(uint16 data) {
	uint16 mask = (1U << 15U);
	uint8 upper_pos = 0U;
	uint8 pos = 15U;
	while(mask > 0U) {
		if((data & mask) != 0U) {
			upper_pos = pos;
			mask >>= 1U;
			break ;
		}
		pos--;
		mask >>= 1U;
	}
	while(mask > 0U) {
		if((data & mask) != 0U) {
			upper_pos++;
			break ;
		}
		mask >>= 1U;
	}
	return upper_pos;
}

uint8 calc_round_log2(uint16 data) {
	uint16 mask = (1U << 15U);
	uint8 upper_pos = 0U;
	uint8 pos = 15U;
	while(mask > 0U) {
		if((data & mask) != 0U) {
			upper_pos = pos;
			mask >>= 1U;
			break ;
		}
		pos--;
		mask >>= 1U;
	}
	if(mask > 0U) {
		if((data & mask) != 0U) {
			upper_pos++;
		}
		mask >>= 1U;
	}
	return upper_pos;
}



/*
 *  For any unsigned integer data, it can be represented by the following formulation.
 *  data = coef*2^exp.
 *
 *  This function calculates the coef and exp for the given data.
 *
 * */
void calc_coeff_and_bexp(uint16 data, uint16* coef, uint8* exp) {
	uint8 zero_count = 0U;
	if(data == 0U) {
		*coef = 0U;
		*exp = 0U;
	} else {
		while(wordop_bittest_at(data, zero_count) == 0U) {
			zero_count++;
		}

		*coef = (data >> zero_count);
		*exp = zero_count;
	}
}

/*
 *  For any unsigned integer data, it can be represented by the following formulation.
 *  data = coef*2^exp.
 *
 *  This function calculates the coef and exp for the given data with the coeff can not be greater than max_coeff.
 *  With the limit function, in some casees, coef may be calculated to a floating value, and it will be casted to
 *  an integer coef, so the calculated  coef*2^exp may be less than the given data.
 * */
void calc_limit_coeff_and_bexp(uint16 data, uint16 max_coeff, uint16* coef, uint8* exp) {
	uint8 zero_count = 0U;
	uint16 coeff_temp = 0U;
	if(data == 0U) {
		*coef = 0U;
		*exp = 0U;
	} else {
		while(wordop_bittest_at(data, zero_count) == 0U) {
			zero_count++;
		}

		coeff_temp = (data >> zero_count);
		while(coeff_temp > max_coeff) {
			coeff_temp >>= 1U;
			zero_count++;
		}
		*coef = coeff_temp;
		*exp = zero_count;
	}
}

uint16 calc_greast_common_divisor(uint16 a, uint16 b) {
	uint16 c;
	while(b != 0) {
		c = (a % b);
		a = b;
		b = c;
	}
	return a;
}

/*
 * Return the Lease Common multiple of the two numbers.
 * Note: The user must ensure that the result of the LCM will
 * not be greater than 0xFFFFU.
 * */
uint16 calc_least_common_multiple(uint16 a, uint16 b) {
	uint16 gcd;
	uint16 _c;
	uint16 _b = b;
	uint16 _a = a;
	while(_b != 0) {
		_c = (_a % _b);
		_a = _b;
		_b = _c;
	}
	gcd = _a;
	_c = (uint16)(((uint32)a * (uint32)b) / (uint32)gcd);
	return _c;
}

uint16 calc_round_div(uint16 a, uint16 b) {
	uint32 data = ((uint32)a << 3U);
	uint16 result;
	data = (data / b);
	if((data & 0x4U) > 0U) {
		result = (uint16)(data >> 3U) + 1U;
	} else {
		result = (uint16)(data >> 3U);
	}
	return result;
}



/*
 * Calculate the least common multiple of periods(size of 16-bit) in the specified configuration set.
 *
 * */
uint16 calc_period_lcm_16bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count) {
	uint8 index;
	uint16 period;
	uint16 period_lcm = 0U;
	const uint8 *period_ptr = config + field_offset_in_byte;
	for(index = 0; index < config_count; index++) {
		period = *((const uint16*)period_ptr);
		period_ptr += entry_size_in_byte;
		if(period == 0U) {
			continue ;
		}
		while((period & 0x0001U) == 0U) {
			period >>= 1U; /*To avoid any overflow when calculate the lcm, the multiple of 2 of this number are removed. */
		}
		if(period_lcm == 0U) { /*set the first number as lcm*/
			period_lcm = period;
		} else if((period_lcm % period) != 0U) {/*The calculated LCM is not a multiple of this number*/
			period_lcm = calc_least_common_multiple(period_lcm, period); /*calculate lcm of two numbers*/
		}
	}
	if(period_lcm == 0U) {
		period_lcm = 0xFFFFU;
	} else {
		while((period_lcm & 0x8000U) == 0U) {
			period_lcm <<= 1U;
		}
	}
	return period_lcm;
}

/*
 * Sort numbers in a configuration set to the target array.
 * Each configuration is a struct, and the number to be sorted
 * is one on the fields.
 * */
void sort_number_8bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, ByteopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint8 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint8*)number_ptr);
		insert_pos = sorted_count;
		for(indexj = 0U; indexj < sorted_count; indexj++) {
			if(number < sort_result[indexj].number) {
				insert_pos = indexj;
				break ;
			}
		}
		indexj = sorted_count;
		while(indexj >= (insert_pos + 1U)) {
			sort_result[indexj].number = sort_result[indexj - 1U].number;
			sort_result[indexj].index = sort_result[indexj - 1U].index;
			indexj--;
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

void remove_sorted_number_by_index_8bit(ByteopSortResult *sorted_result, uint8 number_count, uint8 target_index) {
	uint8 index;
	uint8 target_sorted_index = 0xFFU;
	for(index = 0x00U; index < number_count; index++) {
		if(sorted_result[index].index == target_index) {
			target_sorted_index = index;
			break ;
		}
	}
	if(target_sorted_index != 0xFFU) {
		for(index = target_sorted_index; index < (number_count - 1U); index++) {
			sorted_result[index].number = sorted_result[index + 1U].number;
			sorted_result[index].index = sorted_result[index + 1U].index;
		}
	}
}

/*
 * Sort numbers in a configuration set to the target array.
 * Each configuration is a struct, and the number to be sorted
 * is one on the fields.
 * */
void sort_number_16bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, WordopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint16 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint16*)number_ptr);
		insert_pos = sorted_count;
		for(indexj = 0U; indexj < sorted_count; indexj++) {
			if(number < sort_result[indexj].number) {
				insert_pos = indexj;
				break ;
			}
		}
		indexj = sorted_count;
		while(indexj >= (insert_pos + 1U)) {
			sort_result[indexj].number = sort_result[indexj - 1U].number;
			sort_result[indexj].index = sort_result[indexj - 1U].index;
			indexj--;
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

void remove_sorted_number_by_index_16bit(WordopSortResult *sorted_result, uint8 number_count, uint8 target_index) {
	uint8 index;
	uint8 target_sorted_index = 0xFFU;
	for(index = 0x00U; index < number_count; index++) {
		if(sorted_result[index].index == target_index) {
			target_sorted_index = index;
			break ;
		}
	}
	if(target_sorted_index != 0xFFU) {
		for(index = target_sorted_index; index < (number_count - 1U); index++) {
			sorted_result[index].number = sorted_result[index + 1U].number;
			sorted_result[index].index = sorted_result[index + 1U].index;
		}
	}
}

/*
 * Sort numbers in a configuration set to the target array.
 * Each configuration is a struct, and the number to be sorted
 * is one on the fields.
 * */
void sort_number_32bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, DwordopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint32 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint32*)number_ptr);
		insert_pos = sorted_count;
		for(indexj = 0U; indexj < sorted_count; indexj++) {
			if(number < sort_result[indexj].number) {
				insert_pos = indexj;
				break ;
			}
		}
		indexj = sorted_count;
		while(indexj >= (insert_pos + 1U)) {
			sort_result[indexj].number = sort_result[indexj - 1U].number;
			sort_result[indexj].index = sort_result[indexj - 1U].index;
			indexj--;
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

void remove_sorted_number_by_index_32bit(DwordopSortResult *sort_result, uint8 number_count, uint8 target_index) {
	uint8 index;
	uint8 target_sorted_index = 0xFFU;
	for(index = 0x00U; index < number_count; index++) {
		if(sort_result[index].index == target_index) {
			target_sorted_index = index;
			break ;
		}
	}
	if(target_sorted_index != 0xFFU) {
		for(index = target_sorted_index; index < (number_count - 1U); index++) {
			sort_result[index].number = sort_result[index + 1U].number;
			sort_result[index].index = sort_result[index + 1U].index;
		}
	}
}

void sort_number_8bit_binary(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, ByteopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos, last_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint8 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint8*)number_ptr);
		if(sorted_count == 0U) {
			insert_pos = 0U;
		} else {
			last_pos = sorted_count - 1U;
			if(number > sort_result[last_pos].number) {
				insert_pos = sorted_count;
			} else if(number < sort_result[0U].number) {
				insert_pos = 0U;
			} else {
				uint8 min_index = 0U;
				uint8 max_index = last_pos;
				uint8 mid_index;
				while(min_index < max_index) {
					mid_index = (uint8)((min_index + max_index) / 2U);
					if(number > sort_result[mid_index].number) {
						min_index = mid_index + 1U;
					} else {
						max_index = mid_index;
					}
				}
				insert_pos = min_index;
			}
			for(indexj = last_pos; indexj >= insert_pos; indexj--) {
				sort_result[indexj + 1U].number = sort_result[indexj].number;
				sort_result[indexj + 1U].index = sort_result[indexj].index;
			}
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

void sort_number_16bit_binary(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, WordopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos, last_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint16 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint16*)number_ptr);
		if(sorted_count == 0U) {
			insert_pos = 0U;
		} else {
			last_pos = sorted_count - 1U;
			if(number > sort_result[last_pos].number) {
				insert_pos = sorted_count;
			} else if(number < sort_result[0U].number) {
				insert_pos = 0U;
			} else {
				uint8 min_index = 0U;
				uint8 max_index = last_pos;
				uint8 mid_index;
				while(min_index < max_index) {
					mid_index = (uint8)((min_index + max_index) / 2U);
					if(number > sort_result[mid_index].number) {
						min_index = mid_index + 1U;
					} else {
						max_index = mid_index;
					}
				}
				insert_pos = min_index;
			}
			for(indexj = last_pos; indexj >= insert_pos; indexj--) {
				sort_result[indexj + 1U].number = sort_result[indexj].number;
				sort_result[indexj + 1U].index = sort_result[indexj].index;
			}
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

void sort_number_32bit_binary(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, DwordopSortResult *sort_result) {
	uint8 indexi;
	int8 indexj;
	uint8 sorted_count = 0U;
	uint8 insert_pos, last_pos;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint32 number;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint32*)number_ptr);
		if(sorted_count == 0U) {
			insert_pos = 0U;
		} else {
			last_pos = sorted_count - 1U;
			if(number > sort_result[last_pos].number) {
				insert_pos = sorted_count;
			} else if(number < sort_result[0U].number) {
				insert_pos = 0U;
			} else {
				uint8 min_index = 0U;
				uint8 max_index = last_pos;
				uint8 mid_index;
				while(min_index < max_index) {
					mid_index = (uint8)((min_index + max_index) / 2U);
					if(number > sort_result[mid_index].number) {
						min_index = mid_index + 1U;
					} else {
						max_index = mid_index;
					}
				}
				insert_pos = min_index;
			}
			for(indexj = last_pos; indexj >= insert_pos; indexj--) {
				sort_result[indexj + 1U].number = sort_result[indexj].number;
				sort_result[indexj + 1U].index = sort_result[indexj].index;
			}
		}
		sort_result[insert_pos].number = number;
		sort_result[insert_pos].index = indexi;

		sorted_count++;
		number_ptr += entry_size_in_byte;
	}
}

uint8  find_config_index_from_sort_result_8bit(ByteopSortResult *sort_result, uint8 config_count, uint8 number) {
	uint8 config_index = 0xFFU;
	uint8 min_index = 0U;
	uint8 max_index = (config_count - 1U);
	uint8 mid_index;
	while(min_index < max_index) {
		mid_index = (uint8)(((min_index + max_index) / 2U));
		if(number > sort_result[mid_index].number) {
			min_index = (mid_index + 1U);
		} else {
			max_index = mid_index;
		}
	}
	if((min_index == max_index) && number == sort_result[min_index].number) {
		config_index = sort_result[min_index].index;
	}
	return config_index;
}

uint8  find_config_index_from_sort_result_16bit(WordopSortResult *sort_result, uint8 config_count, uint16 number) {
	uint8 config_index = 0xFFU;
	uint8 min_index = 0U;
	uint8 max_index = (config_count - 1U);
	uint8 mid_index;
	while(min_index < max_index) {
		mid_index = (uint8)(((min_index + max_index) / 2U));
		if(number > sort_result[mid_index].number) {
			min_index = (mid_index + 1U);
		} else {
			max_index = mid_index;
		}
	}
	if((min_index == max_index) && number == sort_result[min_index].number) {
		config_index = sort_result[min_index].index;
	}
	return config_index;
}

//TODO, ml, class5, 32bit comparison function is temporarily truncated
uint8  find_config_index_from_sort_result_32bit(DwordopSortResult *sort_result, uint8 config_count, uint32 number) {
	uint8 config_index = 0xFFU;
	uint8 min_index = 0U;
	uint8 max_index = (config_count - 1U);
	uint8 mid_index;
	uint16 number_16bit = (uint16)number;
	while(min_index < max_index) {
		mid_index = (uint8)(((min_index + max_index) / 2U));
		if(number_16bit > sort_result[mid_index].number) {
			min_index = (mid_index + 1U);
		} else {
			max_index = mid_index;
		}
	}
	if((min_index == max_index) && (number_16bit) == sort_result[min_index].number) {
		config_index = sort_result[min_index].index;
	}
	return config_index;
}


uint8 find_config_from_field_8bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, uint8 target_number) {
	uint8 indexi;
	uint8 number;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint8 config_index = 0xFFU;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint8*)number_ptr);
		if(number == target_number) {
			config_index = indexi;
			break ;
		}

		number_ptr += entry_size_in_byte;
	}
	return config_index;
}

uint8 find_config_from_field_16bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, uint16 target_number) {
	uint8 indexi;
	uint16 number;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint8 config_index = 0xFFU;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint16*)number_ptr);
		if(number == target_number) {
			config_index = indexi;
			break ;
		}

		number_ptr += entry_size_in_byte;
	}
	return config_index;
}

uint8 find_config_from_field_32bit(const uint8 *config, uint8 entry_size_in_byte, uint8 field_offset_in_byte, uint8 config_count, uint32 target_number) {
	uint8 indexi;
	uint32 number;
	const uint8 *number_ptr = config + field_offset_in_byte;
	uint8 config_index = 0xFFU;
	for(indexi = 0U; indexi < config_count; indexi++) {
		number = *((const uint32*)number_ptr);
		if(number == target_number) {
			config_index = indexi;
			break ;
		}

		number_ptr += entry_size_in_byte;
	}
	return config_index;
}

void comath_init_crc32(CoMathCrcParamType *crc_param_pointer) {
	crc_param_pointer->current_crc = 0xFFFFFFFFUL;
}

void comath_calc_crc32(CoMathCrcParamType *crc_param_pointer)
{
	uint16     table_index;    /* Index for CRC table access */
	uint16     source_index;   /* Index for source data buffer */
	uint16     byte_count;
	uint32     tmp_crc;
	uint8      current_data;

	/* Operate on local copy of CRC */
	tmp_crc     = crc_param_pointer->current_crc;
	byte_count  = crc_param_pointer->crc_byte_count;

	/* Loop all input bytes */
	for (source_index = 0u; source_index < byte_count; source_index++) {
		/* Read current data byte */
		current_data = crc_param_pointer->crc_source_buffer[source_index];
		table_index  = (uint16)(((current_data >>4)^ (tmp_crc>>28)) & CRC32_TABLE_SIZE_MASK);
		/* Calculate CRC with small table in ROM */
    	/* Calculate high-nibble first */
    	tmp_crc      = ((tmp_crc) << CRC_INDEX_BITS) ^ CRC32_TABLE[table_index];

		/* Calculate low-nibble */
		table_index  = (uint16)(((current_data & CRC32_TABLE_SIZE_MASK)^ (tmp_crc>>28)) & CRC32_TABLE_SIZE_MASK);
		tmp_crc      = (tmp_crc<<CRC_INDEX_BITS) ^ CRC32_TABLE[table_index];
	}
	/* Update external CRC value */
	crc_param_pointer->current_crc = tmp_crc;
}

static const uint8 crc8_tab[256] = {
		0x0, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
		0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb,
		0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e,
		0x25, 0x38, 0x1f, 0x2, 0x51, 0x4c, 0x6b, 0x76,
		0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4,
		0x6f, 0x72, 0x55, 0x48, 0x1b, 0x6, 0x21, 0x3c,
		0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x4, 0x19,
		0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1,
		0x13, 0xe, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40,
		0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8,
		0xde, 0xc3, 0xe4, 0xf9, 0xaa, 0xb7, 0x90, 0x8d,
		0x36, 0x2b, 0xc, 0x11, 0x42, 0x5f, 0x78, 0x65,
		0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7,
		0x7c, 0x61, 0x46, 0x5b, 0x8, 0x15, 0x32, 0x2f,
		0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0xa,
		0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2,
		0x26, 0x3b, 0x1c, 0x1, 0x52, 0x4f, 0x68, 0x75,
		0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d,
		0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8,
		0x3, 0x1e, 0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50,
		0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2,
		0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x7, 0x1a,
		0x6c, 0x71, 0x56, 0x4b, 0x18, 0x5, 0x22, 0x3f,
		0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7,
		0x35, 0x28, 0xf, 0x12, 0x41, 0x5c, 0x7b, 0x66,
		0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e,
		0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab,
		0x10, 0xd, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43,
		0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1,
		0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x9,
		0x7f, 0x62, 0x45, 0x58, 0xb, 0x16, 0x31, 0x2c,
		0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4,
};

uint8 calc_crc8(const uint8* Crc_DataPtr, uint32 Crc_Length, uint8 Crc_StartValue8, boolean Crc_IsFirstCall ){
    uint8 crc = 0;
    uint32 byte;

    if (Crc_DataPtr != NULL) {

        crc = (TRUE == Crc_IsFirstCall) ? CRC8_START_VALUE : (Crc_StartValue8 ^ CRC8_XOR);

        for (byte = 0; byte < Crc_Length; byte++) {
            crc = crc8_tab[crc ^ *Crc_DataPtr];
            Crc_DataPtr++;
        }

        /* Only XOR value if any calculation was done */
        crc = crc ^ CRC8_XOR;
    }

    return crc;
}

